package com.unitd.base.frame.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.thoughtworks.xstream.XStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtilsBean;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 对象工具类
 *
 * @author Hudan
 * @version 1.0
 * @filename ObjectUtils.java
 * @copyright www.unitd.com
 * @date 2019-01-23
 */
@Slf4j
public class BeanUtils extends org.springframework.beans.BeanUtils {

    /**
     * 判断对象是否为Null
     *
     * @param obj 需要进行判断的对象
     * @return boolean
     */
    public static boolean isNull(Object obj) {
        return obj == null;
    }

    /**
     * 将字符串类型的Object对象转换为字符串
     *
     * @param obj 需要转换的Object对象
     * @return String
     */
    public static String toStr(Object obj) {
        if (BeanUtils.isNull(obj)) return null;

        String val = String.valueOf(obj);
        if (StringUtils.isNull(val)) return null;
        return val;
    }

    /**
     * 将数字转换成字符串
     *
     * @param obj    需要转换成字符串的数字
     * @param defVal 默认值
     * @return String
     */
    public static String toStr(Object obj, String defVal) {
        if (BeanUtils.isNull(obj)) return defVal;

        String val = String.valueOf(obj);
        if (StringUtils.isNull(val)) return defVal;
        return val;
    }

    /**
     * 将Object转换为int类型
     *
     * @param obj 字符串数据
     */
    public static int toInt(Object obj) {
        if (isNull(obj)) {
            return 0;
        } else {
            if (obj instanceof Integer) {
                return ((Integer) obj).intValue();
            } else if (obj instanceof Long) {
                return ((Long) obj).intValue();
            } else {
                return Integer.parseInt((String) obj);
            }
        }
    }

    /**
     * 将Object转换为long类型
     *
     * @param obj 字符串数据
     */
    public static long toLong(Object obj) {
        if (isNull(obj)) {
            return 0L;
        } else {
            return (long) obj;
        }
    }

    /**
     * 将Object转换为float类型
     *
     * @param obj 字符串数据
     */
    public static float toFloat(Object obj) {
        if (isNull(obj)) {
            return 0f;
        } else {
            return (float) obj;
        }
    }

    /**
     * 将Object转换为double类型
     *
     * @param obj 字符串数据
     */
    public static double toDouble(Object obj) {
        if (isNull(obj)) {
            return 0D;
        } else {
            if (obj instanceof BigDecimal) {
                return ((BigDecimal) obj).doubleValue();
            } else {
                return (Double) obj;
            }
        }
    }

    /**
     * 将Object转换为date类型
     *
     * @param obj 字符串数据
     */
    public static Date toDate(Object obj) {
        if (isNull(obj)) {
            return null;
        } else {
            return (Date) obj;
        }
    }

    /**
     * 对象转JSON
     *
     * @param obj 需要进行转换的对象
     * @return json串
     */
    public static String toJson(Object obj) {
        if (obj == null) {
            return null;
        }
        return JSON.toJSONString(obj);
    }

    /**
     * 按照指定的格式化类型,将对象格式化为JSON格式
     *
     * @param obj  需要进行格式化的对象
     * @param type 格式化类型
     * @return json串
     */
    public static String toJsonOfType(Object obj, SerializerFeature type) {
        if (obj == null) {
            return null;
        }
        return JSON.toJSONString(obj, type);
    }

    /**
     * 对象转XML
     *
     * @param obj 需要进行转换的对象
     * @return xml串
     */
    public static String toXml(Object obj) {
        if (obj == null) {
            return null;
        }
        XStream stream = new XStream();
        stream.autodetectAnnotations(true);
        return stream.toXML(obj);
    }

    /**
     * 将JavaBan实体类转为Map类型,然后返回一个map类型的值(利用Introspector和PropertyDescriptor将Bean --> Map)
     *
     * @param obj 需要进行转换的对象
     * @return Map对象
     */
    public static Map<String, Object> toMap(Object obj) {
        Map<String, Object> params = new HashMap<>(0);
        String name = null;
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);

            for (PropertyDescriptor descriptor : descriptors) {
                name = descriptor.getName();
                if (!"class".equals(name)) {
                    params.put(name, propertyUtilsBean.getNestedProperty(obj, name));
                }
            }
        } catch (Exception e) {
            log.warn("Java对象转换成Map对象失败" + e + ",KEY:" + name);
            e.printStackTrace();
        }
        return params;
    }

    /**
     * 复制对象
     *
     * @param obj 需要复制的对象
     * @return 泛型对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T cpoy(Object obj) {
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(obj);

            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream in = new ObjectInputStream(byteIn);
            return (T) in.readObject();
        } catch (Exception e) {
            log.warn("对象拷贝失败", e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过反射给指定对象为空的属性设置值为null
     *
     * @param bean 需要设置值的对象
     */
    public static void setClassPropDefValue(Object bean) {

        // 获取类的字节文件对象
        Class cls = bean.getClass();
        // 获取该类的所有成员变量
        Field[] fields = cls.getDeclaredFields();
        Method[] methods = cls.getDeclaredMethods();

        for (Field field : fields) {
            try {
                String fieldGetName = parGetName(field.getName());
                if (!checkGetMet(methods, fieldGetName)) {
                    continue;
                }
                Method fieldGetMet = cls.getMethod(fieldGetName, new Class[]{});
                Object fieldVal = fieldGetMet.invoke(bean, new Object[]{});
                if (fieldVal != null) {
                    if ("".equals(fieldVal)) {
                        // 设置些属性是可以访问的
                        // 给变量赋值
                        field.setAccessible(true);
                        field.set(bean, null);
                    }
                }
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    /**
     * 拼接某属性的 get方法
     *
     * @param fieldName 属性名称
     * @return String
     */
    public static String parGetName(String fieldName) {
        if (null == fieldName || "".equals(fieldName)) {
            return null;
        }
        int startIndex = 0;
        if (fieldName.charAt(0) == '_')
            startIndex = 1;
        return "get"
                + fieldName.substring(startIndex, startIndex + 1).toUpperCase()
                + fieldName.substring(startIndex + 1);
    }

    /**
     * 判断是否存在某属性的 get方法
     *
     * @param methods     类的方法
     * @param fieldGetMet get方法名
     * @return boolean
     */
    public static boolean checkGetMet(Method[] methods, String fieldGetMet) {
        for (Method met : methods) {
            if (fieldGetMet.equals(met.getName())) {
                return true;
            }
        }
        return false;
    }
}